package org.example;


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * jdk代理,需要被代理的对象实现接口.
 * 生产的代理对象和原对象互为兄弟关系.同为接口的实现类.
 *
 * System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
 * 默认路径：com/sun/proxy/$Proxy0.class,可以将jdk动态代理类字节码写入文件
 *
 * 还演示 获取方法中参数的注解信息,并和方法中传递的参数值对应起来
 * mybatis中用到这种方式,因为反射时,方法中的参数名全都被抹掉了,变成arg0 arg1了
 * 通过将方法中参数的注解和参数值对应起来,可以在mapper.xml配置中通过 #{方法中参数注解值}
 * 来传递参数
 */

public class AppJdkProxyTest {

    // key method , value  Map数组 [ Map key参数注解名 value值  ]
    // 方法 ,[{ songPara : "朋友"} ]
    public static Map<Method, List<Map<String, Object>>> finalAnnoArgMap = new HashMap();

    // 方法= [ "songPara" ,"authorPara"  ]  解析class时获取
    public static Map<Method, List<String>> annoListMap = null;
    // 方法 = ["朋友","周华健"]  方法调用时获取
    public static Map<Method, Object[]> argListMap = null;

    public static void main(String[] args) {
//        parseAllMethodParamAnnos(ITeacher.class);

        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        parseMethodParamAnnos(ITeacher.class, "singSong");

        System.out.println();

        testProxy();

        dealWithResult();

        printResult();


    }

    private static void printResult() {
        Set<Map.Entry<Method, List<Map<String, Object>>>> entries = finalAnnoArgMap.entrySet();
        for (Map.Entry<Method, List<Map<String, Object>>> me : entries) {
            List<Map<String, Object>> value = me.getValue();
            for (Map<String, Object> map : value
            ) {
                Set<Map.Entry<String, Object>> entries1 = map.entrySet();
                for (Map.Entry<String, Object> me1 : entries1
                ) {
                    System.out.println(me1.getKey()+"---" +me1.getValue());
                }
            }
        }
    }

    private static void dealWithResult() {
        Set<Method> methods = annoListMap.keySet();

        for (Method m : methods
        ) {
            List<String> annoList = annoListMap.get(m);
            Object[] argsArray = argListMap.get(m);
            ArrayList<Map<String, Object>> mapList = new ArrayList<>();
            finalAnnoArgMap.put(m, mapList);

            for (int i = 0; i < annoList.size(); i++) {
                HashMap<String, Object> map = new HashMap<>();
                map.put(annoList.get(i),argsArray[i]);
                mapList.add(map);
            }
        }
    }

    public static void testProxy() {
        TeacherLee teacherLee = new TeacherLee();
        ProxyFactory proxyFactory = new ProxyFactory(teacherLee);


        /**
         *  com.sun.proxy.$Proxy0 extends java.lang.reflect.Proxy implements org.example.ITeacher
         *        proxyInstance
         */
        ITeacher proxyInstance = (ITeacher) proxyFactory.getProxyInstance();

        System.out.println(proxyInstance.getClass());// class com.sun.proxy.$Proxy0
        System.out.println(proxyInstance.getClass().getPackage()); //获取的包名 null

        System.out.println("proxyInstance的hashCode=" + System.identityHashCode(proxyInstance));
//        proxyInstance.teach();
//        proxyInstance.singSong("朋友", "周华健");
        proxyInstance.singSong("青花瓷", "周杰伦");


        System.out.println("\n处理argsMap集合-----------------------");

    }

    public static void parseAllMethodParamAnnos(Class<?> clazz) {
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method m : declaredMethods
        ) {

            Parameter[] parameters = m.getParameters();
            for (Parameter param : parameters
            ) {
                System.out.println(param.getType().getName() + " " + param.getName());
            }
        }
    }

    public static void parseMethodParamAnnos(Class<?> clazz, String methodName) {
        try {
            Method method = clazz.getMethod(methodName, new Class[]{String.class, String.class});
            Parameter[] parameters = method.getParameters();
            annoListMap = new HashMap<>();
            ArrayList<String> paraAnnoList = new ArrayList<>();
            annoListMap.put(method, paraAnnoList);

            for (Parameter parameter : parameters) {
                Annotation[] annotations = parameter.getAnnotations();
                //参数名Parameter: arg0
                System.out.println("参数名Parameter: " + parameter.getName());
                for (Annotation annotation : annotations) {
                    if (annotation instanceof ParamInfo) {
                        ParamInfo paramInfo = (ParamInfo) annotation;
                        //注解的类:org.example.ParamInfo-----注解的value值:scyParam1
                        System.out.println("注解的类:" + paramInfo.annotationType().getName() + "-----注解的value值:" + paramInfo.value());
                        paraAnnoList.add(paramInfo.value());
                        System.out.println();
                    }
                }
            }

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }


}
